package com.umanji.generic.service;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.transaction.annotation.Transactional;

public class GenericService<T, ID extends Serializable> {

    private Class<T> persistentClass;

    protected EntityManager em;

    @SuppressWarnings("unchecked")
    public GenericService() {
    	this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    @PersistenceContext(unitName = "umanji")
    public void setEntityManager(EntityManager entityManager) {
    	this.em = entityManager;
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    public T find(ID id) {
        return em.find(persistentClass, id);
	}
	
	public void persist(T entity) {
		em.persist(entity);
	}
	
	public void merge(T entity) {
		em.merge(entity);
	}
	
	public void remove(T entity) {
		em.remove(entity);
	}

	public void mergedRemove(T entity) {
		em.remove(em.merge(entity));
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findAll() {
		return em.createQuery("Select t from " + persistentClass.getSimpleName() + " t").getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findInRange(int firstResult, int maxResults) {
		return em.createQuery("Select t from " + persistentClass.getSimpleName() + " t").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
	}
	
	public long count() {
		return (Long) em.createQuery("Select count(t) from " + persistentClass.getSimpleName() + " t").getSingleResult();
	}

/* -----------------------------------------------------
    @Override
    public <T> T create(T t) {
        this.em.persist(t);
        return t;
    }

    @Override
    @Transactional(readOnly = true)
    public <T, K> T fetch(Class<T> type, K id) {
        return (T)this.em.find(type, id);
    }

    @Override
    public <K> void delete(Class type, K id) {
        Object ref = this.em.getReference(type, id);
        this.em.remove(ref);
    }

    @Override
    public <T> T update(T t) {
        return (T)this.em.merge(t);
    }
-------------------------------------------------------- */
}
